import os
import json
from datetime import datetime, timezone
from flask import Flask, request, jsonify
from flask_cors import CORS

# --- 配置 ---
app = Flask(__name__)
# 允许所有来源访问 /api/* 路径 (为了方便开发，生产环境应配置更严格的规则)
CORS(app, resources={r"/api/*": {"origins": "*"}})

LEADERBOARD_FILE = "leaderboard.json"
MAX_LEADERBOARD_SIZE = 100  # 可选：限制排行榜存储的最大条目数

# --- 辅助函数 ---


def load_scores():
    """从 JSON 文件加载排行榜数据。"""
    if not os.path.exists(LEADERBOARD_FILE):
        return []  # 文件不存在，返回空列表
    try:
        with open(LEADERBOARD_FILE, "r", encoding="utf-8") as f:
            content = f.read()
            # 处理文件为空或只包含空白字符的情况
            if not content.strip():
                return []
            # 使用 json.loads() 解析从文件中读取的字符串内容
            scores = json.loads(content)
            # 基本验证，确保是列表
            if not isinstance(scores, list):
                print(
                    f"警告: {LEADERBOARD_FILE} 格式错误，不是一个列表。将重置为空列表。"
                )
                return []
            return scores
    except (IOError, json.JSONDecodeError) as e:
        # 打印更具体的错误信息
        print(f"错误：无法加载或解析排行榜文件 {LEADERBOARD_FILE}: {e}")
        # 在出错时返回空列表，避免程序崩溃，但记录错误
        return []


def save_scores(scores):
    """将排行榜数据保存到 JSON 文件。"""
    try:
        # 按分数降序排序后再保存（可选，但方便查看文件）
        scores.sort(key=lambda x: x.get("score", 0), reverse=True)
        # 限制排行榜大小
        if MAX_LEADERBOARD_SIZE > 0:
            scores = scores[:MAX_LEADERBOARD_SIZE]

        with open(LEADERBOARD_FILE, "w", encoding="utf-8") as f:
            json.dump(
                scores, f, indent=4, ensure_ascii=False
            )  # indent美化输出, ensure_ascii=False支持中文
        return True
    except IOError as e:
        print(f"错误：无法保存排行榜文件 {LEADERBOARD_FILE}: {e}")
        return False


# --- API 路由 ---


@app.route("/api/scores", methods=["GET"])
def get_leaderboard():
    """
    获取排行榜数据。
    支持 'limit' 查询参数来限制返回的数量。
    """
    scores = load_scores()
    # 再次排序以确保顺序正确（即使 save_scores 排过序）
    scores.sort(key=lambda x: x.get("score", 0), reverse=True)

    try:
        # 从查询参数获取 limit，默认为 10
        limit_str = request.args.get("limit", "10")
        limit = int(limit_str)
        if limit <= 0:
            limit = 10  # 如果提供无效值，则使用默认值
    except ValueError:
        # 如果 limit 不是有效整数，返回错误或使用默认值
        # 这里选择使用默认值
        limit = 10
        print(f"警告：无效的 'limit' 参数值 '{limit_str}'，使用默认值 {limit}")
        # 或者可以返回 400 错误:
        # return jsonify({"error": "Invalid 'limit' parameter. Must be a positive integer."}), 400

    # 截取排行榜
    limited_scores = scores[:limit]

    return jsonify(limited_scores), 200


@app.route("/api/scores", methods=["POST"])
def submit_score():
    """
    提交新的分数记录。
    需要 JSON 请求体包含 'playerName' 和 'score'。
    """
    if not request.is_json:
        return jsonify({"error": "Request must be JSON"}), 400

    data = request.get_json()

    player_name = data.get("playerName")
    score = data.get("score")

    # --- 输入验证 ---
    errors = {}
    if not player_name or not isinstance(player_name, str) or not player_name.strip():
        errors["playerName"] = "Player name is required and must be a non-empty string."
    elif len(player_name) > 50:  # 对应 OpenAPI 设计中的 maxLength
        errors["playerName"] = "Player name cannot exceed 50 characters."

    if score is None:  # 允许 score 为 0
        errors["score"] = "Score is required."
    elif not isinstance(score, int) or score < 0:  # 对应 OpenAPI 设计中的 minimum
        errors["score"] = "Score must be a non-negative integer."

    if errors:
        return jsonify({"error": "Invalid input data", "details": errors}), 400

    # 清理玩家名称
    player_name = player_name.strip()

    # --- 处理分数 ---
    scores = load_scores()

    # 创建新记录
    timestamp = (
        datetime.now(timezone.utc).isoformat(timespec="seconds").replace("+00:00", "Z")
    )  # ISO 8601 UTC
    new_score_record = {
        "playerName": player_name,
        "score": score,
        "timestamp": timestamp,
    }

    scores.append(new_score_record)

    # 保存更新后的排行榜
    if save_scores(scores):
        # 返回成功创建的记录和 201 状态码
        return jsonify(new_score_record), 201
    else:
        # 如果保存失败，返回服务器错误
        return jsonify({"error": "Server error: Could not save score data."}), 500


# --- 运行应用 ---
if __name__ == "__main__":
    # debug=True 会在代码更改时自动重载，并提供更详细的错误信息
    # 在生产环境中应设为 False
    # host='0.0.0.0' 使服务器可以从网络中的其他机器访问，而不仅仅是本地主机
    app.run(host="0.0.0.0", port=5000, debug=True)
